#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "gpio.h"

struct gpiodev*
        gpiodev_construct(
                int gpionum)
{
	struct gpiodev *dev;

	dev = calloc(1, sizeof(struct gpiodev));
	if (NULL == dev) {
		perror("calloc");
		return NULL;
	}

	snprintf(dev->cnum, CNUM_LEN, "%d", gpionum);
    	snprintf(dev->path_direction, PATH_LEN, "/sys/class/gpio/gpio%d/direction", gpionum);
    	snprintf(dev->path_value, PATH_LEN, "/sys/class/gpio/gpio%d/value", gpionum);

	dev->num = gpionum;
	return dev;
}


void
        gpiodev_deconstruct(
                struct gpiodev *dev)
{
	free(dev);
}


extern int 
        gpiodev_export(
                struct gpiodev *dev)
{
	if (access(dev->path_value, 00) == -1) {
		int fd;

		fd = open("/sys/class/gpio/export", O_WRONLY);
    		if (-1 == fd) {
        		perror("open");
        		return -1;
    		}
			
        	if (write(fd, dev->cnum, (int)strlen(dev->cnum)) != 
		  (int)strlen(dev->cnum)) {
            		perror("write");
            		return -1;
        	}
		close(fd);
    	}
	return 0;
}


extern int
        gpiodev_unexport(
                struct gpiodev *dev)
{
	int fd;

	fd = open("/sys/class/gpio/unexport", O_WRONLY);
    	if (-1 == fd) {
        	perror("open");
        	return -1;
    	}
    	if (write(fd, dev->cnum, (int)strlen(dev->cnum)) != (int)strlen(dev->cnum)) {
        	perror("write");
        	return -1;
    	}
    	close(fd);
	return 0;
}


extern int
        gpiodev_setdir(
                struct gpiodev *dev, int dir) 
{
	int fd;

 	fd = open(dev->path_direction, O_WRONLY);

    	if (-1 == fd) {
        	perror("open");
        	return -1;
    	}

    	if (0 == dir) {
        	if (write(fd, "out", 3) != 3) {
            	perror("write out");
            	return -1;
        	}
    	} else {
        	if (write(fd, "in", 2) != 2) {
            	perror("write in");
            	return -1;
        	}
    	}
    	close(fd);
    	return 0;
}

extern int
        gpiodev_setval(
                struct gpiodev *dev, int value)
{
	int fd;

	fd = open(dev->path_value, O_WRONLY);
    	if (-1 == fd) {
        	perror("open value");
        	return -1;
    	}
    	if (0 == value) {
        	if (write(fd, "0", 1) != 1) {
            		perror("write 0");
            		return -1;
        	}
    	} else {
        	if (write(fd, "1", 1) != 1) {
            	perror("write 1");
            	return -1;
        }
    	}
    	close(fd);
    	return 0;
}

extern int
        gpiodev_getval(
                struct gpiodev *dev)
{
	char buffer[32];
	int len;
	int fd;
	int value;
	
        fd = open(dev->path_value, O_RDONLY);
        if (-1 == fd) {
                perror("open value");
                return -1;
        }
        len = read(fd, buffer, 32);
	if (len < 0) {
        	perror("read");
          	return -1;
     	}
	buffer[len+1] = '\0';
	close(fd);

        return atoi(buffer);
}









